package work.mediway.mdm.biz.service.biz.impl;

import com.mediway.hos.common.utils.spring.SpringUtils;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.Optional;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import work.mediway.mdm.biz.bo.DictPushBO;
import work.mediway.mdm.core.constant.MdmConstant;
import work.mediway.mdm.core.enums.StatusEditEnum;
import work.mediway.mdm.core.service.DataChangeLogService;
import work.mediway.mdm.core.util.DUtil;
import work.mediway.mdm.biz.entity.biz.MdmEditLog;
import work.mediway.mdm.biz.helper.BusinessDatabaseHelper;
import work.mediway.mdm.biz.service.biz.MdmEditLogService;
import work.mediway.mdm.biz.service.common.CommonDictService;
import work.mediway.mdm.biz.vo.dict.DictFieldVO;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2021/4/19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataChangeLogServiceImpl implements DataChangeLogService {

    private final BusinessDatabaseHelper businessDatabaseHelper;
    private final MdmEditLogService mdmEditLogService;

    @Override
    public void saveDictDetailLog(String tableCode, Map<String, Object> oldData, Map<String, Object> newData, String updateUser, StatusEditEnum operaType) {
        tableCode = StrUtil.removePrefixIgnoreCase(tableCode, MdmConstant.SCHEMA_NAME_);
        List<String> primaryKeys = this.businessDatabaseHelper.getPrimaryKey(tableCode);
        List<String> tableRowId = CollUtil.newArrayList();
        JSONObject afterEdit = new JSONObject();
        JSONObject beforeEdit = new JSONObject();

        primaryKeys.forEach(item -> {
            if (ObjectUtil.isNotEmpty(newData.get(item))) {
                tableRowId.add(StrUtil.toString(newData.get(item)));
            }
        });

        // 获取表的所有字段信息
        List<DictFieldVO> column = this.businessDatabaseHelper.getColumn(tableCode);
        for (DictFieldVO fieldVO : column) {
            // 操作之后的数据
            buildDataChange(newData, afterEdit, fieldVO);

            // 操作之前的数据
            buildDataChange(oldData, beforeEdit, fieldVO);
        }

        // 构建MDM_EditLog
        MdmEditLog mdmEditLog = new MdmEditLog();
        mdmEditLog.setTableName(tableCode);
        mdmEditLog.setEditType(Optional.ofNullable(StatusEditEnum.getEnum(operaType.getStatusCode()).getStatusCode()).orElse(""));
        mdmEditLog.setTableRowId(StrUtil.toString(CollUtil.join(tableRowId, StrUtil.COMMA)));
        mdmEditLog.setLastUpdateUserId(updateUser);
        mdmEditLog.setEditUpdateDate(DUtil.splitNow()[0]);
        mdmEditLog.setEditUpdateTime(DUtil.splitNow()[1]);
        mdmEditLog.setBeforeEdit(JSONUtil.toJsonStr(beforeEdit));
        mdmEditLog.setAfterEdit(JSONUtil.toJsonStr(afterEdit));

        this.mdmEditLogService.save(mdmEditLog);

        // 消息推送
        if (!StrUtil.containsAnyIgnoreCase(tableCode, "CT_CodeSystem")) {
            try {
                SpringUtils.getBean(CommonDictService.class).pushDict(new DictPushBO(tableCode, JSONUtil.toJsonStr(newData)));
            } catch (Exception exception) {
                log.error("数据推送异常: {}, 数据: {}", exception.getMessage(), JSONUtil.toJsonStr(newData));
            }
        }
    }

    private void buildDataChange(Map<String, Object> data, JSONObject edit, DictFieldVO fieldVO) {
        JSONObject after = new JSONObject();
        after.set("desc", fieldVO.getFieldDesc());
        after.set("value", ObjectUtil.isEmpty(data.get(fieldVO.getFieldCode())) ? "" : data.get(fieldVO.getFieldCode()).toString());
        after.set("type", fieldVO.getSqlType());
        edit.set(fieldVO.getFieldCode(), after);
    }

    @Async
    @Override
    public void saveDictDetailLog(String tableCode, List<Map<String, Object>> oldData, List<Map<String, Object>> newData, String updateUser, StatusEditEnum operaType) {
        for (int i = 0; i < newData.size(); i++) {
            saveDictDetailLog(tableCode, oldData.get(i), newData.get(i), updateUser, operaType);
        }
    }
}
